package com.whz.governance.http.ribbon.rule;


import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.netflix.loadbalancer.AbstractServerPredicate;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import com.whz.generic.Constants;
import com.whz.governance.http.ribbon.context.RibbonFilterContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.stream.Collectors;


/**
 * @author whz
 */
@Slf4j
public class GreyDeployRule extends AbstractDiscoveryEnabledRule {

    public GreyDeployRule() {
        this(new GreyDeployPredicate());
    }

    public GreyDeployRule(AbstractServerPredicate predicate) {
        super(predicate);
    }


    @Override
    public Server choose(Object key) {
        ILoadBalancer lb = getLoadBalancer();
        List<Server> total = lb.getAllServers();

        List<Server> servers;
        String flag = getGreyHeaderVal();

        if (!StringUtils.isEmpty(flag)) {
            // 查找恢复服务
            servers = total.stream().filter(server -> flag.equalsIgnoreCase(getGreyMetaVal(server)))
                           .collect(Collectors.toList());

            if (CollectionUtils.isEmpty(servers)) {

                log.debug("没有指定的灰度服务,需要在正常的服务中按条件选择");

                servers = getCommonServers(total);
            }
        } else {
            log.debug("没有灰度头,应该过滤掉灰度服务");
            servers = getCommonServers(total);
        }

        // 没有服务
        if (CollectionUtils.isEmpty(servers)) {
            log.error("没有找到服务,服务没启动还是加了tongyu-grey-flag?");
            return null;
        }

        return getPredicate().chooseRoundRobinAfterFiltering(servers, key).orNull();
    }

    /**
     * 过滤掉灰度服务
     *
     * @param total 全部服务
     * @return 过滤了灰度服务的剩余服务
     */
    private static List<Server> getCommonServers(final List<Server> total) {
        return total.stream().filter(server -> StringUtils.isEmpty(getGreyMetaVal(server)))
                    .collect(Collectors.toList());
    }


    private static String getGreyHeaderVal() {
        return java.util.Optional.ofNullable(RibbonFilterContextHolder.getCurrentContext().getAttributes())
                                 .map(attributes -> attributes.get(Constants.GREY_FLAG))
                                 .orElse("");
    }

    private static String getGreyMetaVal(Server server) {
        return java.util.Optional.ofNullable(((NacosServer) server).getMetadata())
                                 .map(meta -> meta.get(Constants.GREY_FLAG))
                                 .orElse("");
    }
}